-------------------------------------------------------------------------------
-- Title      : Automatic sampling of PMOD AD1 for audio
-- Project    : 
-------------------------------------------------------------------------------
-- File       : adcSampler.vhd
-- Author     : Paul W
-- Company    : 
-- Created    : 2012-12-09
-- Last update: 2012-12-12
-- Platform   : 
-- Standard   : VHDL'93
-------------------------------------------------------------------------------
-- Description: Get samples as fast as the sampler is configured and store them
--              in an asynchronous fifo. When the fifo is nearly full, begin
--              reading them out for display. 
--              
-------------------------------------------------------------------------------
-- Copyright (c) 2012 
-------------------------------------------------------------------------------
-- Revisions  :
-- Date        Version  Author  Description
-- 2012-12-09  1.0      paul	Created
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity adcSampler is
  
  port (
    in_clk        : in  std_logic;
    in_rst        : in  std_logic;
    in_ad1_d0     : in  std_logic;
    in_getSamples : in  std_logic;
    out_ad1_cs    : out std_logic;
    out_ad1_sclk  : out std_logic;
    out_ad1Data   : out std_logic_vector(11 downto 0);
    out_ad1DataEn : out std_logic
    );

end entity adcSampler;

architecture rtl of adcSampler is

  -- afifo params
  constant NUM_WORDS       : positive := 256;
  constant WORD_WIDTH      : positive := 16;
  constant AL_EMPTY_LEV    : natural  := 5;
  constant AL_FULL_LEV     : natural  := 10;

  signal sampleClk      : std_logic;
  signal sampleTick     : std_logic;
  signal sampleReady    : std_logic;
  signal sampleReady_d1 : std_logic;
  signal sampleReady_d2 : std_logic;
  signal audioSample    : std_logic_vector(15 downto 0);
  signal audioSample_d1 : std_logic_vector(15 downto 0);

  signal audioWrEn   : std_logic;
  signal audioWrData : std_logic_vector(15 downto 0);
  signal fifo_aEmpty : std_logic;
  signal fifo_empty  : std_logic;
  signal fifo_aFull  : std_logic;
  signal fifo_full   : std_logic;
  signal fifo_re     : std_logic;
  signal fifo_re_d1  : std_logic;
  signal fifo_dout   : std_logic_vector(15 downto 0);
  
begin  -- architecture rtl

  -- Block that samples the AD1. Each sample takes 20 cycles, working at the
  -- reduced clock rate 'sampleClk' (about 1.56 MHz).
  -- Given this, we can sample at 78.125 KHz.
  -- get_samples should be held high to continuously sample
  adc_block_U : entity work.adc_block
    port map (
      clk50        => in_clk,
      data1        => in_ad1_d0,
      sclk         => out_ad1_sclk,
      cs           => out_ad1_cs,
      rst          => in_rst,
      get_samples  => in_getSamples,
      sample_ready => sampleReady,
      sample       => audioSample,
      sampleClk    => sampleClk);

  -- Because the sampleClk is much lower, we need to bring this data into the
  -- 50MHz domain carefully. We will debounce the sampleReady and register the
  -- data.
  -- Use an asynchronous fifo to move the data from the sampleClk domain to the
  -- 50 MHz domain.
  getSampleData_proc : process (sampleClk, in_rst) is
  begin  -- process getSampleData_proc
    if in_rst = '1' then                -- asynchronous reset (active high)
      sampleReady_d1 <= '0';
      sampleReady_d2 <= '0';
      audioSample_d1 <= (others => '0');
      audioWrEn      <= '0';
      audioWrData    <= (others => '0');
    elsif rising_edge(sampleClk) then   -- rising clock edge
      -- Register the AD1 signals
      sampleReady_d1 <= sampleReady;
      sampleReady_d2 <= sampleReady_d1;
      audioSample_d1 <= audioSample;

      --Default the output to NOT enabled
      audioWrEn <= '0';

      -- Only write to the fifo on the rising of the sampleReady
      if sampleReady_d2 = '0' and sampleReady_d1 = '1' then
        if fifo_full /= '1' then
          audioWrEn   <= '1';
          audioWrData <= audioSample_d1;
        end if;
      end if;
      
    end if;
  end process getSampleData_proc;

  -- Store the audio samples on sampleClk
  -- Read the samples when the fifo is almost full w/in_clk
  audioAFIFO_U : entity work.afifo
    generic map (
      NUM_WORDS    => NUM_WORDS,
      WORD_WIDTH   => WORD_WIDTH,
      AL_EMPTY_LEV => AL_EMPTY_LEV,
      AL_FULL_LEV  => AL_FULL_LEV)
    port map (
      in_clkWr   => sampleClk,
      in_clkRd   => in_clk,
      in_rst     => in_rst,
      in_we      => audioWrEn,
      in_re      => fifo_re,
      in_din     => audioWrData,
      out_aEmpty => fifo_aEmpty,
      out_empty  => fifo_empty,
      out_aFull  => fifo_aFull,
      out_full   => fifo_full,
      out_dout   => fifo_dout);

  -- Read the audio samples from the fifo when it is almost full
  audioRead_proc : process (in_clk, in_rst) is
  begin  -- process audioRead_proc
    if in_rst = '1' then                -- asynchronous reset (active high)
      fifo_re    <= '0';
      fifo_re_d1 <= '0';
    elsif rising_edge(in_clk) then      -- rising clock edge
      -- Delay the 're' for output enable
      fifo_re_d1 <= fifo_re;

      -- If the fifo has filled up, start outputting the data
      if fifo_aFull = '1' then
        fifo_re <= '1';
      else
        fifo_re <= '0';
      end if;
      
    end if;
  end process audioRead_proc;

  -- Map the fifo outputs to the outside world
  out_ad1DataEn <= fifo_re_d1;
  out_ad1Data   <= fifo_dout(11 downto 0);
  
end architecture rtl;
